package pers.cz.transform;

import javassist.*;

import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

/**
 * @program: postgirl-collection-client
 * @description: ParamsAndReurnTransformer
 * @author: Cheng Zhi
 * @create: 2022-03-01 18:08
 **/
public class ParamsAndReurnMybatisTransformer implements ITransformer{

    public final String TEST_CLASS_NAME = "org.apache.ibatis.session.defaults.DefaultSqlSession";   // mybatis

    public final String METHOD_NAME = "selectList";                                                 // mybatis

    @Override
    public void doInert(String... params) {

    }

    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        String finalClassName = className.replace("/", ".");
        if (finalClassName.equals(TEST_CLASS_NAME)) {
            // 动态修改代码
            try {
                ClassPool classPool = new ClassPool(true);
                classPool.insertClassPath(new LoaderClassPath(loader));
                // 获取目标类
                CtClass ctClass = classPool.get(TEST_CLASS_NAME);
                // 获取要监听的方法
                CtMethod[] declaredMethods = ctClass.getDeclaredMethods();
                String srcBegin = "{pers.cz.mock.ParamsAndReturnMock.begin(parameter);}";

                for (int i=0; i<declaredMethods.length; i++) {
                    if (declaredMethods[i].getName().equals(METHOD_NAME) && declaredMethods[i].getParameterTypes().length == 3) {
                        //declaredMethods[i].insertBefore(srcBegin);
                        //declaredMethods[i].insertAfter(srcEnd);
                        CtMethod copy = CtNewMethod.copy(declaredMethods[i], declaredMethods[i].getName() + "$agent", ctClass, null);
                        ctClass.addMethod(copy);
                        String src =
                                "{" +
                                        "long begin = System.nanoTime();" +
                                        " Object responseMock = pers.cz.mock.ParamsAndReturnMybatisMock.begin($1, $2);" +
                                        " if (responseMock != null) {" +
                                        "       System.out.println(\"-----直接返回，不查询真实的数据库---\");" +
                                        "       return ($r)responseMock;" +
                                        "}" +
                                        " Object result = " + declaredMethods[i].getName()+ "$agent($$);" +
                                        " long end = System.nanoTime();" +
                                        " System.out.println(\"-----方法调用耗时---\" + (end-begin) + \"-------\");" +
                                        " System.out.println(\"-----返回结果---\" + ($r)result + \"-------\");" +
                                        " String method = Thread.currentThread().getStackTrace()[1].getMethodName();" +
                                        " pers.cz.mock.ParamsAndReturnMybatisMock.end($1, $2, result, method);" +
                                        " return ($r)result;" +
                                        "}";
                        declaredMethods[i].setBody(src);
                    }
                }
                CtMethod beginMethod = ctClass.getDeclaredMethod(METHOD_NAME);

                // 加载到jvm
                return ctClass.toBytecode();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}
